home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Amster - Download
- ** Copyright © 1999-2000 by Gürer Özen
- ** Copyright © 2000-2001 by Jacob Laursen
- **
- ** This program is free software; you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation; either version 2 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program; if not, write to the Free Software
- ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
- #include "amster.h"
-
- #include <proto/dos.h>
- #include <proto/asl.h>
- #include <exec/memory.h>
- #include <libraries/dos.h>
- #include <libraries/asl.h>
-
- #include "network.h"
-
- #include <MUI/NListview_mcc.h>
- #include <MUI/NFloattext_mcc.h>
- #include "md5.h"
- #include "amster_Cat.h"
-
-
- int dl_count = 0;
- int QueueCount = 0;
- int WaitingCount = 0;
-
- /* Private functions */
-
- ULONG dl_new(struct IClass *cl, Object *obj, struct opSet *msg);
- void dl_startq(struct TransferData *data, char *title, char *user, u_long ip, int port);
- void dl_startqi(struct TransferData *data, long key);
- void dl_checkqueue(struct TransferData *data);
- void DownloadRetry(struct TransferData *data, Object *obj, char *title, char *user, int limit);
- void PollWaiting(struct TransferData *data, Object *obj);
- int dl_filename(songtrans sd);
- char *chkmd5_fromlock(BPTR lock);
- int dl_askfname(char *fname);
- void dl_handlemsg(thread t, int com, APTR data);
- void dl_resume(struct TransferData *data);
- void dl_cps(struct TransferData *data);
- THREAD_DECL(dl_sucker);
-
-
- MUI_DISPATCH(dl_dispatch)
- {
- struct TransferData *data;
-
- switch(msg->MethodID) {
- case OM_NEW:
- return(dl_new(cl, obj, (APTR)msg));
- case MUIM_Window_Setup:
- return(dl_setup(cl, obj, (APTR)msg));
- case MUIM_Window_Cleanup:
- return(dl_muicleanup(cl, obj, (APTR)msg));
- case DL_ADD:
- data = INST_DATA(cl, obj);
- DoMethod(data->list, MUIM_NList_InsertSingle, (songtrans)(((muimsg)msg)->arg1), MUIV_NList_Insert_Bottom);
- return(NULL);
- case DL_START:
- data = INST_DATA(cl, obj);
- dl_startq(data, (char *)(((muimsg)msg)->arg1), (char *)(((muimsg)msg)->arg2), (u_long)(((muimsg)msg)->arg3), (int)(((muimsg)msg)->arg4));
- return(NULL);
- case DL_STARTINCOMING:
- data = INST_DATA(cl, obj);
- dl_startqi(data, (long)(((muimsg)msg)->arg1));
- return(NULL);
- case DL_UPDATE:
- {
- long pos = MUIV_NList_GetPos_Start;
- data = INST_DATA(cl, obj);
- DoMethod(data->list, MUIM_NList_GetPos, (((muimsg)msg)->arg1), &pos);
- DoMethod(data->list, MUIM_NList_Redraw, pos);
- return(NULL);
- }
- case DL_CPS:
- data = INST_DATA(cl, obj);
- dl_cps(data);
- return(NULL);
- case DL_CLEANUP:
- data = INST_DATA(cl, obj);
- TransferCleanup(data);
- return(NULL);
- case DL_CLEANUP_SINGLE:
- data = INST_DATA(cl, obj);
- TransferCleanupSingle(data, (songtrans)(((muimsg)msg)->arg1));
- return NULL;
- case DL_ABORT:
- data = INST_DATA(cl, obj);
- TransferAbort(data);
- return(NULL);
- case DL_RESUME:
- data = INST_DATA(cl, obj);
- dl_resume(data);
- return(NULL);
- case DL_INFO:
- data = INST_DATA(cl, obj);
- TransferInfo(data);
- return(NULL);
- case DL_RESUME_UPDATE:
- {
- songtrans st;
- data = INST_DATA(cl, obj);
-
- DoMethod(data->list, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &st);
- if (st) {
- if (st->state >= DLS_ABORT) set(data->BT_Resume, MUIA_Disabled, FALSE);
- }
-
- return(NULL);
- }
- case DL_PLAY:
- {
- songtrans st;
- data = INST_DATA(cl, obj);
-
- DoMethod(data->list, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &st);
- if (!st) return(NULL);
- if (st->state < DLS_DOWN || !(st->fname)) return(NULL);
- prf_event((enum Event)(((muimsg)msg)->arg1), st->fname);
-
- return(NULL);
- }
- case DL_SETERROR:
- data = INST_DATA(cl, obj);
- TransferSetError(data, (char *)(((muimsg)msg)->arg1), (char *)(((muimsg)msg)->arg2), (int)(((muimsg)msg)->arg3));
- return(NULL);
- case DL_RETRY:
- data = INST_DATA(cl, obj);
- DownloadRetry(data, obj, (char *)(((muimsg)msg)->arg1), (char *)(((muimsg)msg)->arg2), (int)(((muimsg)msg)->arg3));
- return(NULL);
- case DL_POLLWAIT:
- data = INST_DATA(cl, obj);
- PollWaiting(data, obj);
- return(NULL);
- case DL_REMWAITING:
- data = INST_DATA(cl, obj);
- if (((songtrans)(((muimsg)msg)->arg1))->state == DLS_WAIT) {
- if (--WaitingCount == 0) DoMethod(_app(obj), MUIM_Application_RemInputHandler, &data->waitnode);
- /* This was the last waiting entry - remove input handler */
- #ifdef AMSTER_DEBUG
- gui_debugf("removed waiting - dl_count: %d, QueueCount: %d, waiting: %d", dl_count, QueueCount, WaitingCount);
- #endif
- }
- return(NULL);
- case DL_SETDELAY:
- data = INST_DATA(cl, obj);
- data->waitnode.ihn_Millis = (int)(((muimsg)msg)->arg1)*1000;
- return(NULL);
- case DL_WATCHER:
- data = INST_DATA(cl, obj);
- TransferWatcher(data);
- return(NULL);
- case DL_COUNTDECREMENT:
- data = INST_DATA(cl, obj);
- if (--dl_count == 0) DoMethod(_app(obj), MUIM_Application_RemInputHandler, &data->watchnode);
- dl_checkqueue(data);
- return(NULL);
- case DL_COUNTINCREMENT:
- data = INST_DATA(cl, obj);
- if (dl_count++ == 0) DoMethod(_app(obj), MUIM_Application_AddInputHandler, &data->watchnode);
- return(NULL);
- case DL_CHECKQUEUE:
- data = INST_DATA(cl, obj);
- dl_checkqueue(data);
- return(NULL);
- }
- return(DoSuperMethodA(cl, obj, msg));
- }
-
-
- ULONG dl_new(struct IClass *cl, Object *obj, struct opSet *msg)
- {
- static struct Hook downlistdispHook = { {0,0}, &translistdisp, NULL, NULL };
- struct TransferData *data;
- Object *list, *info, *playbut, *abortbut, *resbut, *cleanbut;
-
- if (obj = (Object *)DoSuperNew(cl, obj,
- MUIA_HelpNode, "download",
- MUIA_Window_Title, MSG_DL_TITLE,
- MUIA_Window_ID, MAKE_ID('D','O','W','N'),
- WindowContents, VGroup,
- Child, list = NListviewObject,
- MUIA_NListview_NList, NListObject,
- InputListFrame,
- MUIA_Font, MUIV_Font_Tiny,
- MUIA_NList_Title, TRUE,
- MUIA_NList_Format, "BAR, BAR, BAR, BAR, BAR",
- MUIA_NList_DisplayHook, &downlistdispHook,
- MUIA_NList_DragSortable, TRUE,
- MUIA_CycleChain, 1,
- End,
- End,
- Child, info = TextObject,
- TextFrame,
- MUIA_Background, MUII_TextBack,
- MUIA_Text_PreParse, "\33c",
- End,
- Child, HGroup,
- Child, HGroup,
- Child, playbut = SimpleButton(MSG_DL_PLAY_GAD),
- MUIA_ShortHelp, MSG_PLAY_HELP,
- End,
- Child, HSpace(4),
- Child, HGroup,
- Child, abortbut = SimpleButton(MSG_DL_ABORT_GAD),
- MUIA_ShortHelp, MSG_ABORT_HELP,
- End,
- Child, HGroup,
- Child, resbut = SimpleButton(MSG_DL_RESUME_GAD),
- MUIA_ShortHelp, MSG_RESUME_HELP,
- End,
- Child, HSpace(4),
- Child, HGroup,
- Child, cleanbut = SimpleButton(MSG_DL_CLEANUP_GAD),
- MUIA_ShortHelp, MSG_CLEANUP_HELP,
- End,
- End,
- End,
- TAG_MORE, msg->ops_AttrList))
- {
- data = INST_DATA(cl,obj);
- data->list = list;
- data->info = info;
- data->BT_Resume = resbut;
-
- data->ihnode.ihn_Object = obj;
- data->ihnode.ihn_Millis = 1000;
- data->ihnode.ihn_Method = DL_CPS;
- data->ihnode.ihn_Flags = MUIIHNF_TIMER;
-
- data->waitnode.ihn_Object = obj;
- data->waitnode.ihn_Millis = prf->QueueDelay*1000; /* Poll interval in milliseconds */
- data->waitnode.ihn_Method = DL_POLLWAIT;
- data->waitnode.ihn_Flags = MUIIHNF_TIMER;
-
- data->watchnode.ihn_Object = obj;
- data->watchnode.ihn_Millis = 10000;
- data->watchnode.ihn_Method = DL_WATCHER;
- data->watchnode.ihn_Flags = MUIIHNF_TIMER;
-
- DoMethod(playbut, MUIM_Notify, MUIA_Pressed, FALSE, obj, 2, DL_PLAY, PRFE_PLAYMP3 );
- DoMethod(resbut, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, DL_RESUME );
- DoMethod(abortbut, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, DL_ABORT );
- DoMethod(cleanbut, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, DL_CLEANUP);
-
- DoMethod(list, MUIM_Notify, MUIA_NList_EntryClick, MUIV_EveryTime, obj, 1, DL_INFO);
- DoMethod(list, MUIM_Notify, MUIA_NList_DoubleClick, MUIV_EveryTime, obj, 2, DL_PLAY, PRFE_DL_DCLICK);
-
- DoMethod(obj, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, gui->iconpanel, 1, PANEL_CLOSEDL);
-
- return((ULONG)obj);
- }
-
- return(0);
- }
-
-
- void dl_addq(song s)
- /* This is the initial function, called from resultview.c */
- {
- songtrans sd;
-
- #ifdef AMSTER_DEBUG
- gui_debug("dl_addq()");
- #endif
- sd = malloc(sizeof(_songtrans));
- if (!sd) return;
- memset(sd, 0, sizeof(_songtrans));
-
- sd->song = nap_songdup(s);
- if (!sd->song) {
- free(sd);
- return;
- }
-
- sd->size = s->size;
- sd->mynick = prf->user;
- sd->type = TYPE_DOWNLOAD_OUT;
- sd->reqtime = GetDateStamp();
-
- if (dl_count >= prf->DownloadQueueLimit && prf->DownloadQueueLimit < 26) {
- sd->state = DLS_QUEUE;
- QueueCount++;
- }
- else {
- sprintf(nap_buf, "\"%s\" \"%s\"", s->user, s->title);
- nap_send(NAPC_FILEINFOREQ);
- sd->state = DLS_PREP;
- DoMethod(gui->dwin, DL_COUNTINCREMENT);
- }
-
- #ifdef AMSTER_DEBUG
- gui_debugf("new download count: %d (concurrent setting: %d), queue count: %d", dl_count, prf->DownloadQueueLimit, QueueCount);
- #endif
-
- DoMethod(gui->dwin, DL_ADD, sd);
- }
-
-
- void dl_startq(struct TransferData *data, char *title, char *user, u_long ip, int port)
- /* This is the initial function, when the actual download is about to
- take place (acknowledged by server) - called from napster.c (via DL_START) */
- {
- u_long tmp;
- songtrans sd;
- long i;
-
- #ifdef AMSTER_DEBUG
- gui_debugf("port : %d (file: %s, user: %s)", port, title, user);
- #endif
-
- for (i=0; ; i++) {
- DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
- if (!tmp) return;
- sd = (songtrans)tmp;
- if ((sd->state == DLS_PREP || sd->state == DLS_WAIT || sd->state == DLS_QUEUE) && stricmp(user,sd->song->user)==0 && strcmp(title,sd->song->title)==0) break;
- }
-
- if (sd->t) {
- #ifdef AMSTER_DEBUG
- gui_debug("this shouldn't happen (1)!");
- #endif
- return; /* Already in a thread */
- }
-
- if (!dl_filename(sd)) {
- if (sd->state == DLS_WAIT) DoMethod(gui->dwin, DL_REMWAITING, sd);
- else if (sd->state == DLS_QUEUE) QueueCount--;
- else {
- sd->state = DLS_ABORT;
- DoMethod(gui->dwin, DL_COUNTDECREMENT);
- }
- sd->state = DLS_ABORT;
- DoMethod(gui->dwin, DL_UPDATE, sd);
- return;
- }
-
- prf_event(PRFE_DLSTART, sd->fname);
-
- #ifdef AMSTER_DEBUG
- gui_debugf("ack [%s] - IP: %ld", title, ip);
- #endif
-
- sd->song->ip = ip; /* In case of browse result, the IP isn't already there */
-
- sd->ip = ip;
- sd->port = port;
- sd->s = -1;
- sd->oldsize = sd->cur;
-
- if (sd->state == DLS_WAIT) DoMethod(gui->dwin, DL_REMWAITING, sd);
-
- /*
- if (dl_count >= prf->DownloadQueueLimit && prf->DownloadQueueLimit < 26) return;
- */
- /* Simply do not spawn the thread if the download is queued. This shouldn't
- be possible though. */
-
- if (sd->state == DLS_QUEUE) {
- QueueCount--;
- DoMethod(gui->dwin, DL_COUNTINCREMENT);
- }
- else if (sd->state == DLS_WAIT) {
- DoMethod(gui->dwin, DL_COUNTINCREMENT);
- }
-
- sd->state = DLS_PREP;
-
- if (port == 0) {
- /* The other user is behind firewall, so we'll wait for him to make the connection.
- After that we spawn the thread. */
- sd->type = TYPE_DOWNLOAD_IN;
- gui_debugf("User %s is behind firewall, so we send alternate download request.", user);
- sprintf(nap_buf, "%s \"%s\"", user, title);
- nap_send(NAPC_ALTDLREQ);
- }
- else {
- sd->t = th_spawn(dl_handlemsg, "Amster downloader", &dl_sucker, prf->DownloadTaskPri, sd);
- if (!sd->t) {
- sd->state = DLS_ERROR;
- DoMethod(gui->dwin, DL_UPDATE, sd);
- }
- }
- }
-
-
- void dl_startqi(struct TransferData *data, long key)
- /* This is the initial function, when a firewalled download is about to
- take place (acknowledged by other client) - called from napster.c (via DL_STARTINCOMING) */
- {
- u_long tmp;
- long len;
- long s;
- songtrans sd;
- long i;
- char *user, *title;
- int size;
- char *buffer;
- char *test;
-
- buffer = malloc(512);
- test = buffer;
- /* Add error handling */
-
- len = sprintf(buffer, "%ld", 0);
- gui_debugf("result: %d, buffer(addr: %x/len: %d): %s", len, &buffer, strlen(buffer), buffer);
-
- s = ObtainSocket(key, AF_INET, SOCK_STREAM, 0);
-
- gui_debugf("dl_startqi (socket: %ld)", s);
-
- /* Make sure we have bsdsocket.library open etc. */
-
- len = recv(s, buffer, 511, 0);
- if (len < 1) {
- /* Clean up here! */
- gui_debugf("net error: %ld/%ld", len, Errno());
- CloseSocket(s);
- free(buffer);
- DoMethod(gui->dwin, DL_COUNTDECREMENT);
- return;
- }
- buffer[len] = '\0';
-
- gui_debugf("from listener thread (len: %ld): %s\n", len, buffer);
-
- user = nap_token(&buffer);
- title = nap_token(&buffer);
- size = nap_ltoken(&buffer);
-
- gui_debugf("parsed: %s/%s/%ld", user, title, size);
-
- free(buffer);
- buffer=malloc(512);
-
- /*
- len = sprintf(buffer, "%ld", 0);
- gui_debugf("result: %d, buffer(addr: %x/len: %d): %s", len, &buffer, strlen(buffer), buffer);
- */
-
- for (i=0; ; i++) {
- DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
- if (!tmp) {
- /* "INVALID REQUEST" etc. + cleanup here */
- CloseSocket(s);
- free(buffer);
- return;
- }
- sd = (songtrans)tmp;
- if ((sd->state == DLS_PREP) && stricmp(user,sd->song->user)==0 && strcmp(title,sd->song->title)==0) break;
- }
-
- gui_debugf("found! - cur: %ld", sd->cur);
-
- len = sprintf(buffer, "%ld", sd->cur);
- gui_debugf("result: %d, buffer(addr: %x/len: %d): %s", len, &buffer, strlen(buffer), buffer);
-
- len = send(s, buffer, strlen(buffer), 0);
- if (len < 1) {
- gui_debugf("result: %d/%d", len, Errno());
- CloseSocket(s);
- free(buffer);
- sd->state = DLS_ERROR;
- sd->error = ERROR_UNKNOWN;
- DoMethod(gui->dwin, DL_UPDATE, sd);
- DoMethod(gui->dwin, DL_COUNTDECREMENT);
- return;
- }
-
- free(buffer);
-
- if (sd->t) {
- gui_debug("this shouldn't happen (1)!");
- CloseSocket(s);
- sd->state = DLS_ERROR;
- DoMethod(gui->dwin, DL_UPDATE, sd);
- DoMethod(gui->dwin, DL_COUNTDECREMENT);
- return; /* Already in a thread */
- }
-
- /* Spawn thread etc. */
-
- sd->s = ReleaseSocket(s, GetUniqueID());
- /* This is NOT the socket descriptor, but a key we can use to get it in the download thread */
-
- sd->t = th_spawn(dl_handlemsg, "Amster downloader (firewall)", &dl_sucker, prf->DownloadTaskPri, sd);
- if (!sd->t) {
- sd->state = DLS_ERROR;
- DoMethod(gui->dwin, DL_UPDATE, sd);
- DoMethod(gui->dwin, DL_COUNTDECREMENT);
- }
- }
-
-
- void dl_checkqueue(struct TransferData *data)
- {
- u_long tmp;
- songtrans sd;
- long i;
-
- if (dl_count >= prf->DownloadQueueLimit && prf->DownloadQueueLimit < 26) return;
-
- for (i=0; ; i++) {
- DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
- if (!tmp) return;
- sd = (songtrans)tmp;
- if (sd->state == DLS_QUEUE) break;
- }
-
- sd->reqtime = GetDateStamp(); /* Reset time to avoid watcher timeouts */
-
- sprintf(nap_buf, "\"%s\" \"%s\"", sd->song->user, sd->song->title);
- nap_send(NAPC_FILEINFOREQ);
- DoMethod(gui->dwin, DL_COUNTINCREMENT);
- sd->state = DLS_PREP;
- QueueCount--;
-
- #ifdef AMSTER_DEBUG
- gui_debugf("queue spawn - new dl_count: %d/QueueCount: %d (%s)", dl_count, QueueCount, sd->song->title);
- #endif
-
- DoMethod(gui->dwin, DL_UPDATE, sd);
- }
-
-
- void DownloadRetry(struct TransferData *data, Object *obj, char *title, char *user, int limit)
- /* Called from napster.c when a file cannot be downloaded yet (busy) */
- {
- u_long tmp;
- songtrans sd;
- long i;
-
- #ifdef AMSTER_DEBUG
- gui_debugf("queue full (server rejection): %s", title);
- #endif
- for (i=0; ; i++) {
- DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
- if (!tmp) return;
- sd = (songtrans)tmp;
- if (sd->state == DLS_PREP && strcmp(sd->song->title, title) == 0 && stricmp(sd->song->user, user) == 0) break;
- }
-
- if (sd->RetryCount >= prf->QueueRetries) return; /* We've already given up */
- else if (limit == 0) {
- sd->state = DLS_ERROR;
- sd->error = ERROR_TEASER; /* Queue limit is 0 = file can't be downloaded by anyone */
-
- DoMethod(gui->dwin, DL_COUNTDECREMENT);
- }
- else {
- sd->state = DLS_WAIT;
- sd->ErrorCode = limit;
- WaitingCount++;
-
- if (WaitingCount == 1) DoMethod(_app(obj), MUIM_Application_AddInputHandler, &data->waitnode);
- /* This is the first waiting entry - add input handler */
-
- DoMethod(gui->dwin, DL_COUNTDECREMENT);
- /* We consider this queued and let other downloads start */
- }
-
- DoMethod(gui->dwin, DL_UPDATE, sd);
- }
-
-
- void PollWaiting(struct TransferData *data, Object *obj)
- {
- u_long tmp;
- songtrans sd;
- long i;
-
- #ifdef AMSTER_DEBUG
- gui_debug("PollWaiting()");
- #endif
-
- if (dl_count >= prf->DownloadQueueLimit && prf->DownloadQueueLimit < 26) {
- #ifdef AMSTER_DEBUG
- gui_debug("- cancelled due to local download count limit!");
- #endif
- return;
- }
-
- if (WaitingCount == 0) return; /* Don't waste time! */
-
- for (i=0; ; i++) {
- DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
- if (!tmp) return;
- sd = (songtrans)tmp;
- if (sd->state == DLS_WAIT && QueueCount == 0) {
- if (sd->RetryCount < prf->QueueRetries) {
- #ifdef AMSTER_DEBUG
- gui_debugf("Repeating request for '%s'", sd->song->title);
- #endif
- sprintf(nap_buf,"\"%s\" \"%s\"", sd->song->user, sd->song->title);
- nap_send(NAPC_FILEINFOREQ);
- sd->RetryCount++;
- }
- else { /* We give up! */
- sd->state = DLS_ERROR;
- sd->error = ERROR_BUSY;
- DoMethod(gui->dwin, DL_REMWAITING, sd);
- DoMethod(gui->dwin, DL_UPDATE, sd);
- }
- }
- }
- }
-
-
- void dl_resume(struct TransferData *data)
- {
- u_long item;
- songtrans sd;
-
- #ifdef AMSTER_DEBUG
- gui_debug("dl_resume()");
- #endif
- DoMethod(data->list, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &item);
- if (!item) return;
-
- sd = (songtrans)item;
- if (sd->state < DLS_ABORT) return; /* Can't resume files that's already in progress */
- #ifdef AMSTER_DEBUG
- gui_debug("1");
- #endif
- if (sd->t) return;
- #ifdef AMSTER_DEBUG
- gui_debug("2");
- #endif
-
- if (dl_count >= prf->DownloadQueueLimit && prf->DownloadQueueLimit < 26) {
- sd->state = DLS_QUEUE;
- QueueCount++;
- }
- else {
- #ifdef AMSTER_DEBUG
- gui_debug("3");
- #endif
- sd->reqtime = GetDateStamp();
- sprintf(nap_buf, "\"%s\" \"%s\"", sd->song->user, sd->song->title);
- nap_send(NAPC_FILEINFOREQ);
- sd->state = DLS_PREP;
- DoMethod(gui->dwin, DL_COUNTINCREMENT);
- }
-
- #ifdef AMSTER_DEBUG
- gui_debugf("download count (resume): %d", dl_count);
- #endif
-
- set(data->BT_Resume, MUIA_Disabled, TRUE);
- DoMethod(gui->dwin, DL_UPDATE, sd);
- }
-
-
- int dl_filename(songtrans sd)
- {
- BPTR lock;
- ALIGNED struct FileInfoBlock fib;
- char md5[80] = "";
- char *fname, temp[108];
- long oldsize=0;
- int way, reqrc;
- char *expl, *choice;
-
- fname = malloc(512);
- if (!fname) return 0;
- strcpy(fname, prf->dlpath);
- strncpy(temp, nap_strippath(sd->song->title), 107);
- temp[107] = '\0';
- AddPart(fname, temp, 511);
-
- if (prf->askfile) {
- if (!dl_askfname(fname)) return 0;
- }
- else { /* Needs optimization and elegance */
- if (strlen(nap_strippath(sd->song->title)) > prf->NameLength) {
- strcpy(fname+strlen(fname)-strlen(nap_strippath(sd->song->title))-4+prf->NameLength, fname+strlen(fname)-4);
- }
- }
-
- lock = Lock(fname, ACCESS_READ);
- if (!lock) {
- sd->fname = fname;
- sd->cur = 0;
- return(1);
- }
-
- if (Examine(lock, &fib)) {
- oldsize = fib.fib_Size;
- sscanf(fib.fib_Comment, "md5: %[^;]", &md5);
- if (md5[0] == 0 && oldsize >= 300032) strcpy(md5, chkmd5_fromlock(lock));
- else UnLock(lock);
- }
- else UnLock(lock);
-
- if (sd->size <= oldsize) {
- way = 1;
- expl = (char *)MSG_DL_RESBIGSIZE;
- choice = (char *)MSG_DL_OVERCANCEL_GAD;
- }
- else if (md5[0] == 0) {
- way = 0;
- expl = (char *)MSG_DL_NOMD5INFO;
- choice = (char *)MSG_DL_RESUMECANCEL_GAD;
- }
- else if (strcmp(md5,sd->song->md5)!=0) {
- way = 1;
- expl = (char *)MSG_DL_NOMATCH;
- choice = (char *)MSG_DL_OVERCANCEL_GAD;
- }
- else {
- way = 2;
- expl = (char *)MSG_DL_RESMATCH;
- choice = (char *)MSG_DL_RESUMEOVER_GAD;
- }
-
- reqrc = MUI_Request(gui->app, gui->win, 0L,
- (char *)MSG_DL_RESUME_INFO,
- choice,
- (char *)MSG_DL_RESUME_MSG,
- fname,
- oldsize,
- sd->size,
- md5[0]==0 ? (char*)MSG_DL_NOMD5 : md5,
- sd->song->md5,
- expl);
-
- if (reqrc == 0) return(0);
-
- if ((way==0 || way==2) && reqrc == 1) {
- sd->fname = fname;
- sd->cur = oldsize;
- return(1);
- }
-
- if (reqrc == 2) {
- if (dl_askfname(fname)) {
- sd->fname = fname;
- sd->cur = 0;
- return(1);
- }
- else return(0);
- }
-
- sd->cur = 0;
- sd->fname = fname;
- return(1);
- }
-
-
- char *chkmd5_fromlock(BPTR lock)
- {
- APTR buffer;
- BPTR fh;
- int len;
- char md5[33] = "";
-
- md5_state_t state;
- md5_byte_t digest[16];
- int di;
-
- md5_init(&state);
-
- if (fh = OpenFromLock(lock)) {
- if (buffer = AllocMem(300032, MEMF_ANY)) {
-
- len = Read(fh, buffer, 300032);
- if (len > 0) {
- md5_append(&state, (const md5_byte_t *)buffer, len);
- md5_finish(&state, digest);
- for (di = 0; di < 16; ++di)
- sprintf(md5+di*2, "%02x", digest[di]);
- }
- FreeMem(buffer, 300032);
- }
- Close(fh);
- }
- else UnLock(lock);
-
- return md5;
- }
-
-
- int dl_askfname(char *fname)
- {
- struct FileRequester *freq;
- u_long win;
-
- freq = AllocAslRequestTags(ASL_FileRequest, TAG_DONE);
- if (!freq) return(0);
-
- get(gui->dwin, MUIA_Window_Window, &win);
- if (AslRequestTags(freq,
- ASLFR_Window, win,
- ASLFR_TitleText, MSG_DL_SELECTFILE,
- ASLFR_InitialFile, nap_strippath(fname),
- ASLFR_InitialDrawer, prf->dlpath,
- ASLFR_DoSaveMode, TRUE,
- TAG_DONE)) {
- strcpy(fname, freq->fr_Drawer);
- AddPart(fname, freq->fr_File, 511);
- FreeAslRequest(freq);
- return(1);
- }
- else {
- FreeAslRequest(freq);
- return(0);
- }
- }
-
-
- void dl_handlemsg(thread t, int com, APTR data)
- /* This is the function that receives messages from the download
- thread. It's called when something needs to be done in the
- main thread (i.e. updating the window). */
- {
- songtrans sd=(songtrans)t->data;
-
- switch (com) {
- case THC_STARTUP:
- #ifdef AMSTER_DEBUG
- gui_debug("thread start");
- #endif
- sd->ts = 1;
- nap_sendbuf(NAPC_DLINC, "");
- break;
- case THC_EXIT:
- #ifdef AMSTER_DEBUG
- gui_debugf("thread exit = %ld, file: %s", data, sd->fname);
- #endif
- sd->error = (int)data;
- TransferHandleError(sd);
- sd->ts = 0;
- sd->t = NULL;
- DoMethod(gui->dwin, DL_COUNTDECREMENT);
- nap_sendbuf(NAPC_DLCOMPLETE, "");
- if (sd->state == DLS_FIN && (prf->AutoCleanup == 1 || prf->AutoCleanup == 3)) {
- DoMethod(gui->dwin, DL_CLEANUP_SINGLE, sd);
- break;
- }
- break;
- case DLC_STATE:
- sd->state = (int)data;
- case DLC_UPDATE:
- DoMethod(gui->dwin, DL_UPDATE, sd);
- break;
- case DLC_ADDSHARE:
- DoMethod(gui->shwin, SHARE_ADDFILE, sd->song, sd->fname);
- break;
- #ifdef AMSTER_DEBUG
- default:
- gui_debugf("thread c: %d, d: %ld", com, data);
- #endif
- }
- }
-
-
- void dl_cps(struct TransferData *data)
- {
- songtrans sd;
- u_long item;
- int i;
-
- for (i=0; ; i++) {
- DoMethod(data->list, MUIM_NList_GetEntry, i, &item);
- if (!item) return;
- sd = (songtrans)item;
- if (sd->state == DLS_DOWN) {
- CalculateCps(sd);
- DoMethod(gui->dwin, DL_UPDATE, sd);
- }
- }
- }
-
-
- /* thread code */
-
- THREAD(dl_sucker)
- {
- thread t;
- songtrans sd;
- struct Library *DOSBase;
- struct Library *SocketBase;
- char *buffer;
- long tmp;
- long s;
- thmsg m;
- char cmnt[80];
- int count;
-
- t = thr_init();
- if (!t) return;
- sd = t->data;
-
- #ifdef AMSTER_DEBUG
- gui_debug("blah-1");
- #endif
- if (!InitTransferThread(t, sd)) return;
- #ifdef AMSTER_DEBUG
- gui_debug("blah-2");
- #endif
- sd->RetryCount = 0;
- s = sd->s;
- buffer = sd->buffer;
- DOSBase = sd->DOSBase;
- SocketBase = sd->SocketBase;
-
- while (1) {
- u_long sigs;
-
- sigs = Wait(sd->nsigm | sd->msigm);
- if (sigs&(sd->msigm)) {
- m = (thmsg)GetMsg(t->port);
- if (m) {
- if (m->com == THC_EXIT) {
- sd->state = DLS_ABORT;
- thr_message(t, DLC_UPDATE, 0);
- ExitTransferThread(sd, 0);
- return;
- }
- if (!m->isreply) {
- m->isreply=1;
- ReplyMsg((struct Message *)m);
- }
- }
- }
-
- if (sigs&(sd->nsigm)) {
- FD_ZERO(&sd->fds);
- FD_SET(s,&sd->fds);
- sd->tv.tv_sec = 0;
- sd->tv.tv_usec = 0;
-
- switch (sd->state) {
- case DLS_CON:
- if (WaitSelect(s+1,NULL,&sd->fds,NULL,&sd->tv,0) != 1) break;
- {
- sd->state = DLS_REQ;
- tmp = 0;
- IoctlSocket(s, FIONBIO, (char*)&tmp);
- /* Disable non-blocking I/O to the socket */
- }
-
- case DLS_REQ:
- if (WaitSelect(s+1,&sd->fds,NULL,NULL,&sd->tv,0) != 1) break;
- {
- tmp = recv(s, buffer, 1, 0);
- if (tmp != 1) {
- sd->ErrorCode = Errno();
- ExitTransferThread(sd, ERROR_NET);
- return;
- }
- if (buffer[0] != '1') {
- ExitTransferThread(sd, 29);
- return;
- }
- thr_message(t, DLC_UPDATE, 0);
- send(s, "GET", 3, 0);
- sprintf(buffer, "%s \"%s\" %ld", sd->mynick, sd->song->title, sd->cur);
- send(s, buffer, strlen(buffer), 0);
-
- tmp = recv(s, buffer, 32, 0);
- if (tmp < 1) {
- sd->ErrorCode = Errno();
- ExitTransferThread(sd, ERROR_NET);
- return;
- }
- buffer[tmp] = '\0';
-
- if (atoi(buffer) != sd->size) {
- if (strcmp(buffer, "FILE NOT FOUND") == 0 || strcmp(buffer, "FILE NOT SHARED") == 0) {
- ExitTransferThread(sd, ERROR_NOTFOUND);
- return;
- }
- else if (strcmp(buffer, "INVALID REQUEST") == 0) {
- ExitTransferThread(sd, ERROR_INVALIDREQUEST);
- return;
- }
- #ifdef AMSTER_DEBUG
- gui_debugf("error (please report this): %s", buffer);
- #endif
- ExitTransferThread(sd, ERROR_UNKNOWN);
- return;
- }
- sd->state = DLS_INIT;
- }
-
- case DLS_INIT:
- sd->f = Open(sd->fname, MODE_READWRITE);
- if (!sd->f) {
- sd->ErrorCode = IoErr();
- ExitTransferThread(sd, ERROR_FILEOPEN);
- return;
- }
- sprintf(cmnt, "md5:%s; size:%ld; user:%s", sd->song->md5, sd->size, sd->song->user);
- SetComment(sd->fname, cmnt);
- Seek(sd->f, sd->cur, OFFSET_BEGINNING);
- sd->state = DLS_DOWN;
- sd->starttime = GetDateStamp();
- sd->resumestart = sd->cur;
- thr_message(t, DLC_UPDATE, 0);
-
- case DLS_DOWN:
- if (WaitSelect(s+1,&sd->fds,NULL,NULL,&sd->tv,0) != 1) break;
- while (sd->cur < sd->size) {
-
- tmp = recv(s, buffer, 4096, 0);
- if (tmp <= 0) {
- sd->ErrorCode = Errno();
- /* If recv() returns 0 the error is EINPROGRESS
- (Net error 36) - I don't know what's causing
- this, but if not failing the thread will busy-loop */
- ExitTransferThread(sd, ERROR_NET);
- return;
- }
- SetIoErr(0L); /* FWrite doesn't clear IoErr() due to a bug */
- count = FWrite(sd->f, buffer, 1, tmp);
- sd->cur += count;
- if (count != tmp) {
- sd->ErrorCode = IoErr();
- ExitTransferThread(sd, ERROR_FILEWRITE);
- return;
- }
-
- m = (thmsg)GetMsg(t->port);
- if (m) {
- if (m->com == THC_EXIT) {
- thr_message(t, DLC_STATE, (APTR)DLS_ABORT);
- ExitTransferThread(sd, 0);
- return;
- }
- if (!m->isreply) {
- m->isreply = 1;
- ReplyMsg((struct Message *)m);
- }
- }
-
- FD_ZERO(&sd->fds);
- FD_SET(s,&sd->fds);
- }
-
- sd->state = DLS_FIN;
- thr_message(t, DLC_UPDATE, 0);
-
- if ((strlen(sd->song->user)+strlen(sd->host)+9) < 80) sprintf(cmnt, "from %s (@%s)", sd->song->user, sd->host);
- else sprintf(cmnt, "from %s (@%s)", sd->song->user, Inet_NtoA(sd->song->ip));
- /* If the hostname is too long for the file comment, we fall back to the IP */
- SetComment(sd->fname, cmnt);
-
- if (prf->autoadd) thr_message(t, DLC_ADDSHARE, 0);
-
- ExitTransferThread(sd, 0);
- return;
-
- }
- }
- }
-
- ExitTransferThread(sd, 0);
- }
-